iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1
Mobile Development

新手試試用Flutter做Netflix UI系列 第 21

[Day21]Flutter Netflix UI 選擇使用者頁面的載入畫面

  • 分享至 

  • xImage
  •  

大家好,今天用的是FutureBuilder,通常我們使用的資料都是從雲端獲取數據,是一個異步任務,我們可以用FutureBuilder對這種異步更新UI

  const FutureBuilder({
    Key key,
    this.future,
    this.initialData,
    @required this.builder,
  }) : assert(builder != null),
       super(key: key);

先來看這一段先前在做選擇使用者頁面程式,我們假設_users代表某個從雲端獲取的資料

GridView.count(
                        shrinkWrap: true,
                        crossAxisCount: 2,
                        crossAxisSpacing: 16.0,
                        mainAxisSpacing: 16.0,
                        childAspectRatio: 10 / 12,
                        children: List.generate(_users.length,
                            (index) => _buildUser(_users[index])),
                      )

現在我們來做一個異步任務,假裝它從雲端取得的過程,它會花兩秒鐘取得數據

 Future<List<User>> mockNetworkData() async {
    print('future work');
    return Future.delayed(Duration(seconds: 2), () => _users);
  }

接著使用FutureBuilder,看一下snapshot會是什麼樣子吧

FutureBuilder<List<User>>(
                  future: mockNetworkData(),
                  builder: (context,AsyncSnapshot snapshot) {
                    print("snapshot: $snapshot");
                    return Container();
                  }),

AsyncSnapshot中有connectionState、data、error
我們可以看到ConnectionState.waiting變成ConnectionState.done,數據也取得了

flutter: future work
flutter: snapshot: AsyncSnapshot<List<User>>(ConnectionState.waiting, null, null)
flutter: snapshot: AsyncSnapshot<List<User>>(ConnectionState.done, [Instance of 'User', Instance of 'User', Instance of 'User', Instance of 'User', Instance of 'User'], null)

所以我們可以根據不同的ConnectionState去return不同的Widget
FutureBuilder<List>中的List是data的型別

FutureBuilder<List<User>>(
                  future: mockNetworkData(),
                  builder: (context, snapshot) {
                    print("snapshot: $snapshot");
                    if (snapshot.connectionState == ConnectionState.done) {
                      return GridView.count(
                        shrinkWrap: true,
                        crossAxisCount: 2,
                        crossAxisSpacing: 16.0,
                        mainAxisSpacing: 16.0,
                        childAspectRatio: 10 / 12,
                        children: List.generate(snapshot.data.length,
                            (index) => _buildUser(snapshot.data[index])),
                      ); //使用snapshot.data為數據來源
                    }
                    return GridView.count(
                      shrinkWrap: true,
                      crossAxisCount: 2,
                      crossAxisSpacing: 16.0,
                      mainAxisSpacing: 16.0,
                      childAspectRatio: 10 / 12,
                      children: List.generate(4, (index) => _buildWaiting()),
                    );//其他狀態返回一個loading頁面
                  }),

Waiting的Widget只是把原本的做一些小刪減,修改

 _buildWaiting() {
    return Container(
//      color: Colors.red,
      child: Column(
        children: [
          Expanded(
              child: Container(
            color: Colors.white.withOpacity(0.1),
            child: Stack(
              alignment: Alignment.center,
              children: [
//                  Image.asset(user.assetName),
              ],
            ),
          )),
          SizedBox(
            height: 8.0,
          ),
          Text(
            "",
            style: userNameStyle,
          )
        ],
      ),
    );
  }

避免異步任務重新啟動

還有一個問題是每次setState的時候它又會重新創建一次,即又撈一次資料,因為我們傳的是mockNetworkData(),每次build都會執行一次
所以有一個解決辦法是用一個Future來取代mockNetworkData(),然後在initState時讓他執行一次

Future _future;

  @override
  void initState() {
    _future =mockNetworkData();
    super.initState();
  }
FutureBuilder<List<User>>(
                  future: _future,
                  builder: (context,AsyncSnapshot snapshot) {
                    print("snapshot: $snapshot");
                    return Container();
                  }),

之後如果有再需要更新的時候,執行如下程式,它才會重新更新

        _future = mockNetworkData();
            setState(() {});

今天的效果如下
Day21

GitHub連結: flutter-netflix-clone


上一篇
[Day20]Flutter Netflix UI 內部儲存空間
下一篇
[Day22]Flutter Netflix UI搜尋頁面之使用FadeInImage
系列文
新手試試用Flutter做Netflix UI30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言